{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 12: 暗号化されたデータを使ってのディープラーニング\n",
    "\n",
    "このnotebookでは、これまでに学んだテクニックの全てを駆使して、暗号化されたモデルと暗号化されたデータを使ってニューラルネットワークのトレーニング、そして推論をを行います。\n",
    "\n",
    "特に、暗号化されたデータを使って微分を計算できる、\"Autograd Engine\"について紹介します。\n",
    "\n",
    "Authors:\n",
    "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
    "- Jason Paumier - Github: [@Jasopaum](https://github.com/Jasopaum)\n",
    "- Théo Ryffel - Twitter: [@theoryffel](https://twitter.com/theoryffel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step 1: ワーカーの作成とトイデータの準備\n",
    "\n",
    "トイデータはトイモデル（初歩的なモデル）で使用するデータセットの事です"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "import syft as sy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set everything up\n",
    "hook = sy.TorchHook(torch) \n",
    "\n",
    "alice = sy.VirtualWorker(id=\"alice\", hook=hook)\n",
    "bob = sy.VirtualWorker(id=\"bob\", hook=hook)\n",
    "james = sy.VirtualWorker(id=\"james\", hook=hook)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# A Toy Dataset\n",
    "data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]])\n",
    "target = torch.tensor([[0],[0],[1],[1.]])\n",
    "\n",
    "# A Toy Model\n",
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.fc1 = nn.Linear(2, 2)\n",
    "        self.fc2 = nn.Linear(2, 1)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.fc1(x)\n",
    "        x = F.relu(x)\n",
    "        x = self.fc2(x)\n",
    "        return x\n",
    "model = Net()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step 2: モデルとデータの暗号化\n",
    "\n",
    "暗号化は2つのステップで実行されます。ステップ1では、\"Secure Multi-Party Computation\"が整数でしか動作しないため、\"Fixed Precision\"を使って不動小数点型のオブジェクトを整数型にエンコードしますy。これは`.fix_precision()`で実現できます。\n",
    "\n",
    "ステップ2では、`.share()`を使ってデータを実際に暗号化します。この例では`shares`をAliceとBobに分割して送信してします。\n",
    "\n",
    "こので注意すべき点はrequires_gradプロパティをTrueにセットしておくことです。こうしておくことで暗号化されたデータに対してもautogradが適用できるようになります。実をいうと、\"Secure Multi-Party Computation\"は整数でしか動きませんが、PyTorchデフォルトのautogradは不動少数でしか動きません。そのため、私たちは特別なAutogradTensorを自作する必要がありました。`print`関数を使えば各エレメントにAutogradTensorが含まれているかどうか確認できますよ。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 全て暗号化しておきます\n",
    "data = data.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)\n",
    "target = target.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)\n",
    "model = model.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step 3: トレーニング\n",
    "\n",
    "簡単なトレーニングロジックでモデルのトレーニングができます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "opt = optim.SGD(params=model.parameters(),lr=0.1).fix_precision()\n",
    "\n",
    "for iter in range(20):\n",
    "    # 1) 前回の微分の計算結果をクリアしておきます。（もしあれば）\n",
    "    opt.zero_grad()\n",
    "\n",
    "    # 2) 予測を行います\n",
    "    pred = model(data)\n",
    "\n",
    "    # 3) ロスを計算します\n",
    "    loss = ((pred - target)**2).sum()\n",
    "\n",
    "    # 4) 勾配ベクトルを計算します\n",
    "    loss.backward()\n",
    "\n",
    "    # 5) モデルのウェイトを更新します\n",
    "    opt.step()\n",
    "\n",
    "    # 6) 確認のため、状況を出力します\n",
    "    print(loss.get().float_precision())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ロスはちゃんと下がっていますね。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fixed Precisionの影響\n",
    "\n",
    "モデルからデータまで、全てを暗号化してしまって、トレーニングに影響は無いのか、期待通りロスが下がるのか、気になりますよね。でも、暗号化はされていても、行われているコンピューテーションは、理論上は、同じです。実際、暗号化環境下でのトレーニングも通常のトレーニングも結果はほぼ同じです。同じモデルを同じデータで暗号化せずにトレーニングしてみてください。その際には初期値にを固定して、同じものを使う必要があります。\n",
    "\n",
    "モデルを初期化したい場合は、例えば、`__init__`の中で:\n",
    "```\n",
    "with torch.no_grad():\n",
    "    self.fc1.weight.set_(torch.tensor([[ 0.0738, -0.2109],[-0.1579,  0.3174]], requires_grad=True))\n",
    "    self.fc1.bias.set_(torch.tensor([0.,0.1], requires_grad=True))\n",
    "    self.fc2.weight.set_(torch.tensor([[-0.5368,  0.7050]], requires_grad=True))\n",
    "    self.fc2.bias.set_(torch.tensor([-0.0343], requires_grad=True))\n",
    "```\n",
    "を実行してみてください。\n",
    "\n",
    "気がついたかもしれませんが、唯一の違いは\"fixed precision\"を使って少数を整数に変更したり、整数を少数に戻したりする時に誤差が生じるということです。デフォルトの`precision_fractional`の値は3です。この値を2にすると誤差は大きくなります。もし、誤差をさらに小さくしたい場合は`precision_fractional = 4`を試してみても良いかもしれません。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# おめでとうございます！コミュニティに入ろう！\n",
    "\n",
    "本チュートリアルを完了しました。おめでとうございます！もし、このチュートリアルを気に入って、プライバシーに配慮した非中央集権的なAI技術や付随する（データやモデルの）サプライチェーンにご興味があって、プロジェクトに参加したいと思われるなら、以下の方法で可能です。\n",
    "\n",
    "### PySyftのGitHubレポジトリにスターをつける\n",
    "\n",
    "一番簡単に貢献できる方法はこのGitHubのレポジトリにスターを付けていただくことです。スターが増えると露出が増え、より多くのデベロッパーにこのクールな技術の事を知って貰えます。\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### Slackに入る\n",
    "\n",
    "最新の開発状況のトラッキングする一番良い方法はSlackに入ることです。\n",
    "下記フォームから入る事ができます。\n",
    "[http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### コードプロジェクトに参加する\n",
    "\n",
    "コミュニティに貢献する一番良い方法はソースコードのコントリビューターになることです。PySyftのGitHubへアクセスしてIssueのページを開き、\"Projects\"で検索してみてください。参加し得るプロジェクトの状況を把握することができます。また、\"good first issue\"とマークされているIssueを探す事でミニプロジェクトを探すこともできます。\n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### 寄付\n",
    "\n",
    "もし、ソースコードで貢献できるほどの時間は取れないけど、是非何かサポートしたいという場合は、寄付をしていただくことも可能です。寄附金の全ては、ハッカソンやミートアップの開催といった、コミュニティ運営経費として利用されます。\n",
    "\n",
    "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
